package com.ruoyi.worker.service.v2.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.worker.constant.AttendanceSignResultEnum;
import com.ruoyi.worker.domain.v2.*;
import com.ruoyi.worker.mapper.v2.RzAttendanceSumDailyRecordDetailHistoryV2Mapper;
import com.ruoyi.worker.mapper.v2.RzAttendanceSumDailyRecordDetailV2Mapper;
import com.ruoyi.worker.mapper.v2.RzAttendanceSumDailyRecordV2Mapper;
import com.ruoyi.worker.service.v2.RzAttendanceSumDailyRecordDetailV2Service;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import static com.ruoyi.worker.constant.AttendanceSignResultEnum.*;

@Service
public class RzAttendanceSumDailyRecordDetailV2ServiceImpl implements RzAttendanceSumDailyRecordDetailV2Service {

    @Resource
    private RzAttendanceSumDailyRecordDetailV2Mapper detailV2Mapper;
    @Resource
    private RzAttendanceSumDailyRecordDetailHistoryV2Mapper historyV2Mapper;
    @Resource
    private RzAttendanceSumDailyRecordV2Mapper recordV2Mapper;

    @Override
    public Map<String, Integer> detailStatistics(String date, Integer groupId, Integer deptId, Integer signType) {
        return detailV2Mapper.detailStatistics(date, groupId, deptId, signType);
    }

    @Override
    public List<RzAttendanceSumDailyDetailV2VO> detailStatistics2(RzAttendanceSumDailyDetailQueryParameterVO params) {
        List<RzAttendanceSumDailyDetailV2VO> details = detailV2Mapper.detailStatistics2(params);
        Set<Integer> tmp = ImmutableSet.of(1, 3, 7, 8, 9, 11);
        for (RzAttendanceSumDailyDetailV2VO vo : details) {
            List<Integer> result = Arrays.stream(vo.getResults().split(",")).map(Integer::valueOf).collect(Collectors.toList());
            List<Integer> types = Arrays.stream(vo.getTypes().split(",")).map(Integer::valueOf).collect(Collectors.toList());
            List<String> signTimes = null;
            if (StringUtils.isNotEmpty(vo.getTimes())) {
                signTimes = Arrays.stream(vo.getTimes().split(",")).map(String::valueOf).collect(Collectors.toList());
            }
            List<RzAttendanceSumDailyDetailSignResultVO> resultVo = new ArrayList<>();
            Set<Integer> dayTmp = new HashSet<>();
            Set<Integer> nightTmp = new HashSet<>();
            for (int i = 0; i < result.size(); i++) {
                int signResultCode = result.get(i);
                String signResultName = getNameByCode(AttendanceSignResultEnum.class, signResultCode);
                switch (types.get(i)) {
                    case 11:
                        vo.setMorningLabel("早上上班");
                        if (!CollectionUtil.isEmpty(signTimes) && signTimes.size() > i) {
                            vo.setMorningTime(signTimes.get(i));
                        }
//                        vo.setMorningResult(types.get(i));
                        vo.setMorningResult(signResultCode);
                        vo.setMorningResultName(signResultName);
                        dayTmp.add(signResultCode);
                        break;
                    case 12:
                        vo.setAfternoonLabel("中午上班");
                        if (!CollectionUtil.isEmpty(signTimes) && signTimes.size() > i) {
                            vo.setAfternoonTime(signTimes.get(i));
                        }
//                        vo.setAfternoonResult(types.get(i));
                        vo.setAfternoonResult(signResultCode);
                        vo.setAfternoonResultName(signResultName);
                        dayTmp.add(signResultCode);
                        break;
                    case 13:
                        vo.setNightLabel("下午上班");
                        if (!CollectionUtil.isEmpty(signTimes) && signTimes.size() > i) {
                            vo.setNightTime(signTimes.get(i));
                        }
//                        vo.setNightResult(types.get(i));
                        vo.setNightResult(signResultCode);
                        vo.setNightResultName(signResultName);
                        nightTmp.add(signResultCode);
                        break;
                    case 21:
                        vo.setDownWorkLabel("下班");
                        if (!CollectionUtil.isEmpty(signTimes) && signTimes.size() > i) {
                            vo.setDownWorkTime(signTimes.get(i));
                        }
//                        vo.setDownWorkResult(types.get(i));
                        vo.setDownWorkResult(signResultCode);
                        vo.setDownWorkResultName(signResultName);
                        nightTmp.add(signResultCode);
                        break;
                }
            }

            if (Sets.intersection(dayTmp, tmp).size() > 0) {
                vo.setDaySignResult(1);
            } else {
                vo.setDaySignResult(0);
            }

            if (Sets.intersection(nightTmp, tmp).size() > 0) {
                vo.setNightSignResult(1);
            } else {
                vo.setNightSignResult(0);
            }
        }
        return details;
    }

    @Override
    @Transactional
    public void updateAttendanceDaily(List<RzAttendanceSumDailyDetailUpdateVO> params) {
        List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> history = this.saveHistory(params);
        this.updateTotalStatistics(history, params);
        detailV2Mapper.updateSignResult(params);
    }

    private void updateTotalStatistics(List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> history,
                                       List<RzAttendanceSumDailyDetailUpdateVO> params) {

        ImmutableList ins = ImmutableList.of(2, 3, 4, 5, 6, 10);

        List<RzAttendanceSumDailyRecordV2Domain> records =
                recordV2Mapper.recordsWithParams(params.get(0).getDate(), params.get(0).getGroupId(), params.get(0).getDeptId());

        if (records.size() == 2) {
            // 通班记录
            Map<String, int[]> historyMap = this.historyResultMap(history, ins); // 历史记录
            Map<String, int[]> changesMap = this.changeResultMap(params, ins); // 最新记录
            for (Map.Entry<String, int[]> m : changesMap.entrySet()) {
                String idCard = m.getKey();
                int[] historyResult = historyMap.get(idCard);
                if (ObjectUtils.isEmpty(historyResult)) {
                    // 这个分支是不可能存在的
                    continue;
                }
                int[] changeResult = m.getValue();
                // 实际出勤调整
                if (historyResult[0] == 0 && changeResult[0] == 1) {
                    records.get(0).setResult(records.get(0).getResult() + 1);
                } else if (historyResult[0] == 1 && changeResult[0] == 0) {
                    records.get(0).setResult(records.get(0).getResult() - 1);
                }

                if (historyResult[1] == 0 && changeResult[1] == 1) {
                    records.get(1).setResult(records.get(1).getResult() + 1);
                } else if (historyResult[1] == 1 && changeResult[1] == 0) {
                    records.get(1).setResult(records.get(1).getResult() - 1);
                }

                // 各个单项调整【通班的白班】
                if (historyResult[2] == 4 || historyResult[3] == 4) {
                    records.get(0).setNumberOfQuit(records.get(0).getNumberOfQuit() - 1);
                } else if (historyResult[2] == 3 || historyResult[3] == 3) {
                    records.get(0).setNumberOfInjure(records.get(0).getNumberOfInjure() - 1);
                } else if (historyResult[2] == 5 || historyResult[3] == 5) {
                    records.get(0).setNumberOfLeave(records.get(0).getNumberOfLeave() - 1);
                } else if (historyResult[2] == 6 || historyResult[3] == 6) {
                    records.get(0).setNumberOfAbsenteeism(records.get(0).getNumberOfAbsenteeism() - 1);
                }

                if (changeResult[2] == 4 || changeResult[3] == 4) {
                    records.get(0).setNumberOfQuit(records.get(0).getNumberOfQuit() + 1);
                } else if (changeResult[2] == 3 || changeResult[3] == 3) {
                    records.get(0).setNumberOfInjure(records.get(0).getNumberOfInjure() + 1);
                } else if (changeResult[2] == 5 || changeResult[3] == 5) {
                    records.get(0).setNumberOfLeave(records.get(0).getNumberOfLeave() + 1);
                } else if (changeResult[2] == 6 || changeResult[3] == 6) {
                    records.get(0).setNumberOfAbsenteeism(records.get(0).getNumberOfAbsenteeism() + 1);
                }

                // 各个单项调整【通班的晚班】
                if (historyResult[4] == 4 || historyResult[5] == 4) {
                    records.get(1).setNumberOfQuit(records.get(1).getNumberOfQuit() - 1);
                } else if (historyResult[4] == 3 || historyResult[5] == 3) {
                    records.get(1).setNumberOfInjure(records.get(1).getNumberOfInjure() - 1);
                } else if (historyResult[4] == 5 || historyResult[5] == 5) {
                    records.get(1).setNumberOfLeave(records.get(1).getNumberOfLeave() - 1);
                } else if (historyResult[4] == 6 || historyResult[5] == 6) {
                    records.get(1).setNumberOfAbsenteeism(records.get(1).getNumberOfAbsenteeism() - 1);
                }

                if (changeResult[4] == 4 || changeResult[5] == 4) {
                    records.get(1).setNumberOfQuit(records.get(1).getNumberOfQuit() + 1);
                } else if (changeResult[4] == 3 || changeResult[5] == 3) {
                    records.get(1).setNumberOfInjure(records.get(1).getNumberOfInjure() + 1);
                } else if (changeResult[4] == 5 || changeResult[5] == 5) {
                    records.get(1).setNumberOfLeave(records.get(1).getNumberOfLeave() + 1);
                } else if (changeResult[4] == 6 || changeResult[5] == 6) {
                    records.get(1).setNumberOfAbsenteeism(records.get(1).getNumberOfAbsenteeism() + 1);
                }

            }
        } else if (records.size() == 1) {
            // 单班记录
            Map<String, int[]> historyMap = this.historyResultMapSingle(history, ins); // 历史记录
            Map<String, int[]> changesMap = this.changeResultMapSingle(params, ins); // 最新记录
            for (Map.Entry<String, int[]> m : changesMap.entrySet()) {
                String idCard = m.getKey();
                int[] historyResult = historyMap.get(idCard);
                if (ObjectUtils.isEmpty(historyResult)) {
                    // 这个分支是不可能存在的
                    continue;
                }
                int[] changeResult = m.getValue();
                // 实际出勤调整
                if (historyResult[0] == 0 && changeResult[0] == 1) {
                    records.get(0).setResult(records.get(0).getResult() + 1);
                } else if (historyResult[0] == 1 && changeResult[0] == 0) {
                    records.get(0).setResult(records.get(0).getResult() - 1);
                }

                // 单项调整
                if (historyResult[1] == 4) {
                    records.get(0).setNumberOfQuit(records.get(0).getNumberOfQuit() - 1);
                } else if (historyResult[1] == 3) {
                    records.get(0).setNumberOfInjure(records.get(0).getNumberOfInjure() - 1);
                } else if (historyResult[1] == 5) {
                    records.get(0).setNumberOfLeave(records.get(0).getNumberOfLeave() - 1);
                } else if (historyResult[1] == 6) {
                    records.get(0).setNumberOfAbsenteeism(records.get(0).getNumberOfAbsenteeism() - 1);
                }

                if (changeResult[1] == 4) {
                    records.get(0).setNumberOfQuit(records.get(0).getNumberOfQuit() + 1);
                } else if (changeResult[1] == 3) {
                    records.get(0).setNumberOfInjure(records.get(0).getNumberOfInjure() + 1);
                } else if (changeResult[1] == 5) {
                    records.get(0).setNumberOfLeave(records.get(0).getNumberOfLeave() + 1);
                } else if (changeResult[1] == 6) {
                    records.get(0).setNumberOfAbsenteeism(records.get(0).getNumberOfAbsenteeism() + 1);
                }

            }
        }

        recordV2Mapper.updateRecord(records);
    }

    private Map<String, int[]> historyResultMapSingle(List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> history, List ins) {
        Map<String, int[]> map = new HashMap<>();
        for (RzAttendanceSumDailyRecordDetailHistoryV2Domain y : history) {
            int[] arr = map.get(y.getIdCard());
            if (arr == null) {
                arr = new int[]{0, 2};
            }
            if (ins.contains(y.getSignResultBefore())) {
                arr[0] = 0;
                arr[1] = y.getSignResultBefore();
            } else {
                arr[0] = 1;
            }
            map.put(y.getIdCard(), arr);
        }
        return map;
    }

    private Map<String, int[]> changeResultMapSingle(List<RzAttendanceSumDailyDetailUpdateVO> changes, List ins) {
        Map<String, int[]> map = new HashMap<>();
        for (RzAttendanceSumDailyDetailUpdateVO y : changes) {
            int[] arr = map.get(y.getIdCard());
            if (arr == null) {
                arr = new int[]{0, 2};
            }
            if (ins.contains(y.getSignResult())) {
                arr[0] = 0;
                arr[1] = y.getSignResult();
            } else {
                arr[0] = 1;
            }
            map.put(y.getIdCard(), arr);
        }
        return map;
    }


    private Map<String, int[]> changeResultMap(List<RzAttendanceSumDailyDetailUpdateVO> changes, List ins) {
        Map<String, int[]> map = new HashMap<>();
        int[] dInts = new int[]{0, 0, 2, 2};
        int[] nInts = new int[]{0, 0, 2, 2};
        for (RzAttendanceSumDailyDetailUpdateVO y : changes) {
            int[] tmp = map.get(y.getIdCard()); // 出勤矩阵
            if (tmp == null) {
                tmp = new int[]{0, 0, 2, 2, 2, 2};
            }

            if (ImmutableList.of(11, 12).contains(y.getSignType())) {
                if (y.getSignType() == 11) {
                    if (!ins.contains(y.getSignResult())) {
                        dInts[0] = 1;
                    }
                    tmp[2] = y.getSignResult();
                } else if (y.getSignType() == 12) {
                    if (!ins.contains(y.getSignResult())) {
                        dInts[1] = 1;
                    }
                    tmp[3] = y.getSignResult();
                }
            } else {
                if (y.getSignType() == 13) {
                    if (!ins.contains(y.getSignResult())) {
                        nInts[0] = 1;
                    }
                    tmp[4] = y.getSignResult();
                } else if (y.getSignType() == 21) {
                    if (!ins.contains(y.getSignResult())) {
                        nInts[1] = 1;
                    }
                    tmp[5] = y.getSignResult();
                }
            }
            tmp[0] = Math.min(dInts[0], dInts[1]);
            tmp[1] = Math.min(nInts[0], nInts[1]);
            map.put(y.getIdCard(), tmp);
        }
        return map;
    }

    /**
     * @author: 陈宇寰
     * @date: 2022-01-07 17:13:34
     * @params:
     * @return:
     * @description: 历史记录hash化
     */
    private Map<String, int[]> historyResultMap(List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> history, List ins) {
        Map<String, int[]> historyMap = new HashMap<>();
        int[] dInts = new int[]{0, 0, 2, 2};
        int[] nInts = new int[]{0, 0, 2, 2};
        for (RzAttendanceSumDailyRecordDetailHistoryV2Domain y : history) {
            int[] tmp = historyMap.get(y.getIdCard()); // 出勤矩阵
            if (tmp == null) {
                tmp = new int[]{0, 0, 2, 2, 2, 2};
            }

            if (ImmutableList.of(11, 12).contains(y.getSignType())) {
                if (y.getSignType() == 11) {
                    if (!ins.contains(y.getSignResultBefore())) {
                        dInts[0] = 1;
                    }
                    tmp[2] = y.getSignResultBefore();
                } else if (y.getSignType() == 12) {
                    if (!ins.contains(y.getSignResultBefore())) {
                        dInts[1] = 1;
                    }
                    tmp[3] = y.getSignResultBefore();
                }
            } else {
                if (y.getSignType() == 13) {
                    if (!ins.contains(y.getSignResultBefore())) {
                        nInts[0] = 1;
                    }
                    tmp[4] = y.getSignResultBefore();
                } else if (y.getSignType() == 21) {
                    if (!ins.contains(y.getSignResultBefore())) {
                        nInts[1] = 1;
                    }
                    tmp[5] = y.getSignResultBefore();
                }
            }
            tmp[0] = Math.min(dInts[0], dInts[1]);
            tmp[1] = Math.min(nInts[0], nInts[1]);
            historyMap.put(y.getIdCard(), tmp);
        }
        return historyMap;
    }

    @Override
    public List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> histories(String date, List<String> idCards) {
        return historyV2Mapper.getHistories(date, idCards);
    }

    @Override
    public List<Map<String, String>> cardDetails(String date, List<String> idCards) {
        return detailV2Mapper.cardDetail(date, idCards);
    }

    @Override
    public List<DailySignTimesVO> signTimes(String date) throws ParseException {
        String nextDay = DateUtils.getDifferDay(DateUtils.parseDate(date, "yyyy-MM-dd"), 1);
        String startDate = String.format("%s %s", date, "06:00:00");
        String endDate = String.format("%s %s", nextDay, "10:00:00");
        return detailV2Mapper.signTimes(startDate, endDate);
    }

    private List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> saveHistory(List<RzAttendanceSumDailyDetailUpdateVO> params) {
        if (params.size() == 0) {
            return null;
        }
        String workDate = params.get(0).getDate();
        String updateBy = params.get(0).getUpdateBy();
        List<String> idCards = params.stream().map(RzAttendanceSumDailyDetailUpdateVO::getIdCard).collect(Collectors.toList());
        List<Integer> signTypes = params.stream().map(RzAttendanceSumDailyDetailUpdateVO::getSignType).collect(Collectors.toList());
        List<RzAttendanceSumDailyRecordDetailV2Domain> historys = detailV2Mapper.historyDatas(workDate, idCards, signTypes);
        List<RzAttendanceSumDailyRecordDetailHistoryV2Domain> wait4SaveDatas = new ArrayList<>();
        historys.forEach(item -> {
            RzAttendanceSumDailyRecordDetailHistoryV2Domain domain = new RzAttendanceSumDailyRecordDetailHistoryV2Domain(item.getId(), item.getName(), item.getIdCard(),
                    item.getWorkDate(), item.getSignResult(), item.getSignType());
            domain.setCreateBy(updateBy);
            domain.setUpdateBy(updateBy);
            wait4SaveDatas.add(domain);
        });
        historyV2Mapper.saveHistory(wait4SaveDatas);
        return wait4SaveDatas;
    }


}
